package com.uxsino.commons.enums;

import com.google.common.base.Strings;
import com.google.common.collect.Maps;
import io.github.classgraph.ClassGraph;
import io.github.classgraph.ScanResult;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 整合采集枚举的方法
 * 
 * 
 */
@SuppressWarnings({ "unchecked", "rawtypes" })
public class Enums {

    private static Map<String, Enums> bufferPool = Maps.newHashMap();

    static {
        // 加载所有继承 DescribableEnum的类
        if (bufferPool.isEmpty()) {
            ScanResult scanResult = new ClassGraph().verbose().enableAllInfo().whitelistPackages("com").scan();
            scanResult.getClassesImplementing(TypedEnum.class.getName()).forEach(cls -> {
                try {
                    String str = cls.getName();
                    Enums collector = new Enums((Class<? extends TypedEnum>) Class.forName(str));
                    bufferPool.put(str, collector);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
        }
    }

    private Class<? extends TypedEnum> clazz;

    private TypedEnum<?>[] values;

    public static List<Enums> allEnums() {
        return bufferPool.values().stream().collect(Collectors.toList());
    }

    public static Enums forName(String className) {
        return bufferPool.get(className);
    }

    public static Enums forClass(Class<?> clazz) {
        return forName(clazz.getName());
    }

    private <T> Enums(Class<? extends TypedEnum> class1) {
        this.clazz = class1;
    }

    public <T> T keyOfIgnoreCase(Object key) {
        if (key == null || (key instanceof String && Strings.isNullOrEmpty((String) key))) {
            return null;
        }
        TypedEnum<?>[] values = values();
        for (TypedEnum<?> v : values) {
            if (v.key() instanceof String && v.key().toString().equalsIgnoreCase(key.toString())) {
                return (T) v;
            } else {
                if (v.key().equals(key)) {
                    return (T) v;
                }
            }
        }

        return null;
    }

    public <T> T keyOf(Object key) {
        if (key == null || (key instanceof String && Strings.isNullOrEmpty((String) key))) {
            return null;
        }
        TypedEnum<?>[] values = values();
        for (TypedEnum<?> v : values) {
            if (v.key().equals(key)) {
                return (T) v;
            }
        }

        return null;
    }

    public <T> T nameOf(String key) {
        TypedEnum<?>[] values = values();
        for (TypedEnum<?> v : values) {
            if (v.toString().equalsIgnoreCase(key)) {
                return (T) v;
            }
        }

        return null;
    }

    public <T> T descOf(String desc) {
        TypedEnum<?>[] values = values();
        for (TypedEnum<?> v : values) {
            if (v.desc().equalsIgnoreCase(desc)) {
                return (T) v;
            }
        }

        return null;
    }

    public TypedEnum<?>[] values() {
        if (values == null) {
            try {
                Method valuesMethod = clazz.getMethod("values");
                if (valuesMethod != null) {
                    values = (TypedEnum<?>[]) valuesMethod.invoke(clazz);
                }
            } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
                    | InvocationTargetException e) {
            }
        }
        return values;
    }

    public Class<?> getClazz() {
        return clazz;
    }

    public String getName() {
        return clazz.getName();
    }

}
